﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Collections;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Data;
using System.Collections.ObjectModel;
using System.ComponentModel;

namespace MyRssReader
{
    public class FlowItemsControl : Section
    {

        public static DependencyProperty ItemsSourceProperty = DependencyProperty.Register(
            "ItemsSource", typeof(IEnumerable), typeof(FlowItemsControl),
            new PropertyMetadata(null, ItemsSourceChanged));

        public static DependencyProperty ItemTemplateProperty = DependencyProperty.Register(
            "ItemTemplate", typeof(DataTemplate), typeof(FlowItemsControl));

        public static DependencyProperty ItemTemplateSelectorProperty = DependencyProperty.Register(
            "ItemTemplateSelector", typeof(DataTemplateSelector), typeof(FlowItemsControl),
            new PropertyMetadata(null));

        public static DataTemplate GetItemTemplate(DependencyObject d)
        {
            return (DataTemplate)d.GetValue(ItemTemplateProperty);
        }

        public static void SetItemTemplate(DependencyObject d, DataTemplate value)
        {
            d.SetValue(ItemTemplateProperty, value);
            RebuildItems((FlowItemsControl)d);
        }

        public DataTemplate ItemTemplate
        {
            get { return GetItemTemplate(this); }
            set { SetItemTemplate(this, value); }
        }

        public static IEnumerable GetItemsSource(DependencyObject d)
        {
            return (IEnumerable)d.GetValue(ItemsSourceProperty);
        }

        public static void SetItemsSource(DependencyObject d, IEnumerable value)
        {
            d.SetValue(ItemsSourceProperty, value);
        }

        public IEnumerable ItemsSource
        {
            get { return GetItemsSource(this); }
            set { SetItemsSource(this, value); }
        }

        public static DataTemplateSelector GetItemTemplateSelector(DependencyObject d)
        {
            return (DataTemplateSelector)d.GetValue(ItemTemplateSelectorProperty);
        }

        public static void SetItemTemplateSelector(DependencyObject d, DataTemplateSelector value)
        {
            d.SetValue(ItemTemplateSelectorProperty, value);
            RebuildItems((FlowItemsControl)d);
        }

        public DataTemplateSelector ItemTemplateSelector
        {
            get { return GetItemTemplateSelector(this); }
            set { SetItemTemplateSelector(this, value); }
        }


        private static void ItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            RebuildItems((FlowItemsControl)d, (IEnumerable)e.NewValue);
        }

        private ObservableCollection<GroupStyle> groupStyles = new ObservableCollection<GroupStyle>();
        private int level = 0;

        public ObservableCollection<GroupStyle> GroupStyles
        {
            get { return groupStyles; }
            set { groupStyles = value; }
        }

        private static void RebuildItems(FlowItemsControl ctl)
        {
            RebuildItems(ctl, null);
        }

        private static void RebuildItems(FlowItemsControl ctl, IEnumerable items)
        {
            ctl.Blocks.Clear();

            if (items == null)
                items = GetItemsSource(ctl);
            if (items == null) return;

            DataTemplate defaultTemplate = GetItemTemplate(ctl);
            DataTemplateSelector selector = GetItemTemplateSelector(ctl);
            GroupStyle defaultGroupStyle = new GroupStyle();
            defaultGroupStyle.HidesIfEmpty = true;

            ICollectionView view = items as ICollectionView;
            if (view != null && view.GroupDescriptions != null && view.GroupDescriptions.Count > 0)
                items = view.Groups;

            foreach (object item in items)
            {
                Block itemView;
                CollectionViewGroup group = item as CollectionViewGroup;

                if (group != null)
                {
                    GroupStyle style = (ctl.GroupStyles != null && ctl.level < ctl.GroupStyles.Count)
                                           ? ctl.GroupStyles[ctl.level]
                                           : defaultGroupStyle;

                    if (style.HidesIfEmpty && group.ItemCount == 0) continue;

                    DataTemplate template = style.HeaderTemplateSelector != null
                                                ? style.HeaderTemplateSelector.SelectTemplate(group, ctl)
                                                : style.HeaderTemplate;

                    Block header;
                    if (template != null)
                    {
                        header = template.LoadContent() as Block;
                        if (header == null)
                            throw new Exception("Root of DataTemplate must be block element");
                    }
                    else
                    {
                        BindableRun run = new BindableRun();
                        run.SetBinding(BindableRun.BoundTextProperty, "Name");
                        run.FontWeight = FontWeights.Bold;
                        header = new Paragraph(run);
                        header.Margin = new Thickness(2);
                    }

                    itemView = new Section();
                    itemView.DataContext = group;
                    ((Section)itemView).Blocks.Add(header);

                    FlowItemsControl inner = new FlowItemsControl();
                    inner.level = ctl.level + 1;
                    inner.ItemTemplate = ctl.ItemTemplate;
                    inner.ItemTemplateSelector = ctl.ItemTemplateSelector;
                    inner.GroupStyles = ctl.GroupStyles;
                    inner.ItemsSource = group.Items;

                    ((Section)itemView).Blocks.Add(inner);
                }
                else
                {
                    DataTemplate template = selector != null
                                                ? selector.SelectTemplate(item, ctl)
                                                : defaultTemplate;
                    if (template != null)
                    {
                        itemView = template.LoadContent() as Block;
                        if (itemView == null)
                            throw new Exception("Root of DataTemplate must be block element");
                    }
                    else
                    {
                        BindableRun run = new BindableRun();
                        run.SetBinding(BindableRun.BoundTextProperty, string.Empty);
                        itemView = new Paragraph(run);
                        itemView.Margin = new Thickness(1);
                    }
                    itemView.DataContext = item;
                }
                ctl.Blocks.Add(itemView);
            }
        }
    }
}
